import os
import json
import importlib.util
import sys
from typing import List, Dict, Any, Optional
from flask import Flask

class Plugin:
    def __init__(self, id: str, manifest: Dict, instance: Any = None):
        self.id = id
        self.manifest = manifest
        self.instance = instance
        self.enabled = True
        self.config = {}

class PluginManager:
    def __init__(self, plugin_dir: str):
        self.plugin_dir = plugin_dir
        self.plugins: Dict[str, Plugin] = {}
        self.app: Optional[Flask] = None

    def init_app(self, app: Flask):
        """初始化插件管理器"""
        self.app = app
        self.load_plugins()

    def load_plugins(self):
        """加载所有插件"""
        if not os.path.exists(self.plugin_dir):
            return

        for plugin_id in os.listdir(self.plugin_dir):
            self.load_plugin(plugin_id)

    def load_plugin(self, plugin_id: str) -> Optional[Plugin]:
        """加载单个插件"""
        plugin_path = os.path.join(self.plugin_dir, plugin_id)
        manifest_path = os.path.join(plugin_path, 'manifest.json')
        
        if not os.path.isdir(plugin_path) or not os.path.exists(manifest_path):
            return None

        try:
            # 加载manifest
            with open(manifest_path, 'r', encoding='utf-8') as f:
                manifest = json.load(f)

            # 加载插件模块
            if 'backend' in manifest and 'entry' in manifest['backend']:
                module_path = os.path.join(plugin_path, manifest['backend']['entry'])
                if os.path.exists(module_path):
                    spec = importlib.util.spec_from_file_location(plugin_id, module_path)
                    if spec and spec.loader:
                        module = importlib.util.module_from_spec(spec)
                        sys.modules[plugin_id] = module
                        spec.loader.exec_module(module)
                        
                        # 实例化插件类
                        if hasattr(module, 'Plugin'):
                            plugin_instance = module.Plugin()
                            # 初始化插件
                            if hasattr(plugin_instance, 'init'):
                                plugin_instance.init(self.app)
                        else:
                            plugin_instance = None
                    else:
                        plugin_instance = None
                else:
                    plugin_instance = None
            else:
                plugin_instance = None

            # 创建插件对象
            plugin = Plugin(
                id=plugin_id,
                manifest=manifest,
                instance=plugin_instance
            )

            # 加载配置
            config_path = os.path.join(plugin_path, 'config.json')
            if os.path.exists(config_path):
                with open(config_path, 'r', encoding='utf-8') as f:
                    plugin.config = json.load(f)

            # 存储插件
            self.plugins[plugin_id] = plugin
            return plugin

        except Exception as e:
            print(f"Error loading plugin {plugin_id}: {str(e)}")
            return None

    def unload_plugin(self, plugin_id: str) -> bool:
        """卸载插件"""
        if plugin_id not in self.plugins:
            return False

        plugin = self.plugins[plugin_id]
        if plugin.instance and hasattr(plugin.instance, 'destroy'):
            try:
                plugin.instance.destroy()
            except Exception as e:
                print(f"Error destroying plugin {plugin_id}: {str(e)}")

        # 移除模块
        if plugin_id in sys.modules:
            del sys.modules[plugin_id]

        # 移除插件
        del self.plugins[plugin_id]
        return True

    def enable_plugin(self, plugin_id: str) -> bool:
        """启用插件"""
        if plugin_id not in self.plugins:
            return False

        plugin = self.plugins[plugin_id]
        if plugin.instance and hasattr(plugin.instance, 'enable'):
            try:
                plugin.instance.enable()
                plugin.enabled = True
                return True
            except Exception as e:
                print(f"Error enabling plugin {plugin_id}: {str(e)}")
                return False
        return False

    def disable_plugin(self, plugin_id: str) -> bool:
        """禁用插件"""
        if plugin_id not in self.plugins:
            return False

        plugin = self.plugins[plugin_id]
        if plugin.instance and hasattr(plugin.instance, 'disable'):
            try:
                plugin.instance.disable()
                plugin.enabled = False
                return True
            except Exception as e:
                print(f"Error disabling plugin {plugin_id}: {str(e)}")
                return False
        return False

    def get_plugin_config(self, plugin_id: str) -> Optional[Dict]:
        """获取插件配置"""
        if plugin_id in self.plugins:
            return self.plugins[plugin_id].config
        return None

    def update_plugin_config(self, plugin_id: str, config: Dict) -> bool:
        """更新插件配置"""
        if plugin_id not in self.plugins:
            return False

        plugin = self.plugins[plugin_id]
        plugin.config.update(config)

        # 保存配置到文件
        config_path = os.path.join(self.plugin_dir, plugin_id, 'config.json')
        try:
            with open(config_path, 'w', encoding='utf-8') as f:
                json.dump(plugin.config, f, indent=4)
            return True
        except Exception as e:
            print(f"Error saving config for plugin {plugin_id}: {str(e)}")
            return False

    def get_plugins(self) -> List[Dict]:
        """获取所有已安装的插件信息"""
        return [{
            'id': plugin.id,
            'manifest': plugin.manifest,
            'enabled': plugin.enabled,
            'icon': f'/plugins/{plugin.id}/{plugin.manifest.get("frontend", {}).get("icon", "")}'
        } for plugin in self.plugins.values()]

    def get_plugin_by_id(self, plugin_id: str) -> Optional[Dict]:
        """获取指定插件的信息"""
        if plugin_id in self.plugins:
            plugin = self.plugins[plugin_id]
            return {
                'id': plugin.id,
                'manifest': plugin.manifest,
                'enabled': plugin.enabled,
                'config': plugin.config,
                'icon': f'/plugins/{plugin.id}/{plugin.manifest.get("frontend", {}).get("icon", "")}'
            }
        return None 